<template>
  <div>
    <!-- Fixed Header Placeholder -->
    <div class="fixedHeaderPlaceholder___2MMip"></div>

    <!-- Main Content -->
    <input id="topicId" type="hidden" value="8845"/>
    <input id="isAdmin" type="hidden" value=""/>

    <input id="STATICURL" type="hidden" value="//static.clewm.net/cli"/>

    <div class="warper" id="warper">
      <div class="deqr_container">
        <div class="deqr_main deqr-wrapper">
          <div class="deqr-content">
            <!--
            ============================================
            ⬆️⬆️⬆️ 上方解码区开始 ⬆️⬆️⬆️
            这个区域包含所有的解码功能：摄像头解码、上传图片解码、URL解码
            ============================================
            -->
            <h1 class="deqr-title">二维码解码器</h1>
            <input
              accept=".gif,.jpg,.jpeg,.png,.webp"
              class="deqr_upload_img uploadfile"
              data-uptype="deqr"
              id="filedatacode"
              name="Filedata"
              type="file"
              @change="handleFileUpload"
            />

            <div class="deqr-item-wrapper">
              <!-- Left side - Camera decoder -->
              <div class="deqr-item-left">
                <!-- 摄像头显示区域 - 点击后显示实时画面 -->
                <div style="width: 100%; height: 100%; background: #000; border-radius: 8px; position: relative; display: flex; align-items: center; justify-content: center; border: 1px solid #ddd; overflow: hidden;" v-show="cameraStream">
                  <video
                    ref="testVideo"
                    id="mainCameraVideo"
                    autoplay
                    muted
                    playsinline
                  ></video>

                  <!-- 摄像头控制按钮 -->
                  <div class="camera-controls">
                    <!-- 关闭按钮 -->
                    <div class="camera-control-btn camera-close-btn" @click="stopCamera" title="关闭摄像头">
                      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                        <path d="M18 6L6 18M6 6l12 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
                      </svg>
                    </div>
                    <!-- 全屏按钮 -->
                    <div class="camera-control-btn camera-fullscreen-btn" @click="toggleCameraFullscreen" title="全屏显示">
                      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                        <path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
                      </svg>
                    </div>
                  </div>

                  <!-- 扫描框和动画效果 - 扫码成功时隐藏 -->
                  <div class="scan-overlay" v-show="!scanResult">
                    <!-- 扫描线动画 -->
                    <div class="scanner-line-animation">
                      <div class="scanner-line-animation-inner"></div>
                    </div>

                    <!-- 四个角落的扫描框 -->
                    <div class="scan-corner top-left"></div>
                    <div class="scan-corner top-right"></div>
                    <div class="scan-corner bottom-left"></div>
                    <div class="scan-corner bottom-right"></div>
                  </div>

                  <!-- 顶部文字提示 - 扫码成功时隐藏 -->
                  <div class="scanner-header-text" v-show="!scanResult">
                    扫码提示区域
                  </div>

                  <!-- 底部文字提示 - 扫码成功时隐藏 -->
                  <div class="scanner-bottom-text" v-show="!scanResult">
                    将二维码对准扫描框
                  </div>

                  <!-- 中央提示文字 - 扫码成功时隐藏 -->
                  <div class="scanner-center-text" v-show="!scanResult">
                    <div class="scanner-main-text">将二维码放入框内</div>
                    <div class="scanner-sub-text">自动扫描识别</div>
                  </div>

                  <!-- 扫描结果显示 - 使用与上传解码相同的样式 -->
                  <div class="camera-result-wrapper upload-dropzone-result-wrapper" v-show="scanResult">
                    <div class="result-wrapper">
                      <p class="deqr-success-title" style="color: rgba(0, 0, 0, 0.65)">
                        解码结果 - 第{{ scanTimeNumber }}次扫码
                      </p>
                      <div class="text-wrapper">
                        <div class="title-text">{{ scanResult }}</div>
                        <div class="copy-area" @click="copyScanResult">
                          <div class="drop-down">
                            <span>复制内容</span>
                          </div>
                          <img alt="" src="../../assets/images/e0a71806478e.png"/>
                        </div>
                      </div>
                    </div>
                    <div class="deqr-action-btns-wrapper">
                      <div class="deqr-button-go-home">
                        <div class="drop-down">
                          <span>美化标签、下载其他格式等</span>
                        </div>
                        <span @click.stop="goToHome">前往首页生码</span>
                      </div>
                      <div class="deqr-again-button" @click="scanAgain">再次扫描</div>
                    </div>
                    <div v-if="autoScanEnabled" style="text-align: center; margin-top: 8px; color: rgba(0, 0, 0, 0.45); font-size: 12px;">
                      <span class="scanGap-text">{{ scanGap }}</span>秒后扫描下一个
                    </div>
                  </div>
                </div>

                <div class="__type-scan-content deqr-item" id="deqrcamera" v-show="!cameraStream">
                  <!-- 摄像头未启动时显示的点击按钮区域 -->
                  <div class="deqr-box deqr-box-camera" @click="startCamera">
                    <div class="icon">
                      <div class="deqr-icon deqr-icon-camera"></div>
                    </div>
                    <div class="title">
                      <h2 style="font-size: 16px;font-weight: 400;">摄像头解码</h2>
                      <div style="font-size: 12px;display: flex;justify-content: center; margin-top: 4px;">
                        <h3 class="scanner-camera-text">支持连续扫码，自动保存扫码历史并支持导出Excel文件</h3>
                      </div>
                      <div class="scanner-camera-tips-text"></div>
                    </div>
                    <div class="scanner-setting-button" @click.stop="openScannerSettings">
                      <div class="content">
                        <div class="drop-down">
                          <span>设置文案、音效等</span>
                        </div>
                        <img alt="" src="../../assets/images/ae5fd2ee1615.png"/>
                      </div>
                    </div>
                  </div>
                  <div class="warn-tip none">
                    <i class="fa fa-exclamation-circle"></i>
                    <span></span>
                  </div>
                </div>

                <!-- Scanner wrapper -->
                <div class="scanner-wrapper" :style="{display: showScanner ? 'block' : 'none'}">
                  <div class="scanner">
                    <div class="scan-area">
                      <div class="scan-area-container">
                        <div class="scanner-line-animation">
                          <div class="scanner-line-animation-inner"></div>
                        </div>
                        <div class="scanner-header-text">{{ scannerHeaderText }}</div>
                        <div class="scanner-bottom-text">{{ scannerBottomText }}</div>
                        <div class="scanner-result-wrapper">
                          <div class="scanner-result-content-wrapper">
                            <div class="scanner-result-content">
                              <div class="scanner-result-text">
                                第<span id="scan-time-number-out" style="font-size: 24px;">{{ scanTimeNumber }}</span>次扫码
                              </div>
                              <div class="scanner-result-url">
                                <span class="result-area">{{ scanResult }}</span>
                                <span class="copy-area" @click="copyScanResult">
                                  <span class="drop-down">
                                    <span>复制内容</span>
                                  </span>
                                  <img alt="" src="../../assets/images/e0a71806478e.png"/>
                                </span>
                              </div>
                              <div class="scan-action-btns-wrapper">
                                <div class="scan-again-button" @click="scanAgain">再次扫描</div>
                                <div class="scan-button-go-home">
                                  <div class="drop-down">
                                    <span>美化标签、下载其他格式等</span>
                                  </div>
                                  <span @click.stop="goToHome">前往首页生码</span>
                                </div>
                              </div>
                              <div class="scanner-result-footer">
                                <span class="scanGap-text">{{ scanGap }}</span>秒后扫描下一个
                              </div>
                            </div>
                          </div>
                        </div>
                      </div>
                    </div>
                    <div class="scanner-return-button" @click="returnToMain">
                      <img alt="" src="../../assets/images/ad6ed37e31a5.png"/>
                    </div>
                    <div class="scanner-autoScan-text">
                      <div class="content">已开启连续扫码</div>
                    </div>
                    <div class="scanner-setting-button" @click="openScannerSettings">
                      <div class="content">
                        <img alt="" src="../../assets/images/1db5be77032e.png"/>
                        <span class="desc">设置</span>
                      </div>
                    </div>
                    <div class="scanner-fullscreen-button" @click="toggleFullscreen">
                      <div class="content">
                        <img alt="" src="../../assets/images/d361f35f7b6c.png"/>
                        <span class="desc">全屏</span>
                      </div>
                    </div>
                    <div class="auto-close-button" style="display: none">
                      长时间无操作，摄像头将在1分钟后关闭
                    </div>
                    <video
                      id="scanVideoNew"
                      ref="scanVideo"
                    ></video>
                  </div>
                  <div id="scan-content-new"></div>
                </div>

                <!-- Scanner result wrapper -->
                <div class="scanner-result-wrapper">
                  <div class="scanner-result-content">
                    <div class="scanner-result-text">
                      第<span id="scan-time-number" style="font-size: 24px;">{{ scanTimeNumber }}</span>次扫码
                    </div>
                    <div class="scanner-result-url">
                      <span class="result-area">{{ scanResult }}</span>
                      <span class="copy-area" @click="copyScanResult">
                        <span class="drop-down">
                          <span>复制内容</span>
                        </span>
                        <img alt="" src="../../assets/images/e0a71806478e.png"/>
                      </span>
                    </div>
                    <div class="scan-action-btns-wrapper">
                      <div class="scan-again-button" @click="scanAgain">再次扫描</div>
                      <div class="scan-button-go-home">
                        <div class="drop-down">
                          <span>美化标签、下载其他格式等</span>
                        </div>
                        <span @click.stop="goToHome">前往首页生码</span>
                      </div>
                    </div>
                    <div class="scanner-result-footer">
                      <span class="scanGap-text">{{ scanGap }}</span>秒后扫描下一个
                    </div>
                  </div>
                </div>
                <div class="camera-loading-text" style="display: none;">摄像头启动中...</div>
              </div>

              <!-- Right side - Upload and URL decoder -->
              <div class="deqr-item-right">
                <!-- Upload container -->
                <div>
                  <div class="upload-container" id="img-upload-container">
                    <div
                      class="upload-dropzone"
                      @dragover.prevent="handleDragOver"
                      @dragenter.prevent="handleDragEnter"
                      @dragleave.prevent="handleDragLeave"
                      @drop.prevent="handleDrop"
                      @click="handleDropzoneClick"
                    >
                      <div class="upload-dropzone-content-wrapper">
                        <div class="upload-dropzone-result-wrapper" v-show="showUploadResult">
                          <div class="result-wrapper">
                            <p class="deqr-success-title" style="color: rgba(0, 0, 0, 0.65)">解码结果</p>
                            <div class="text-wrapper">
                              <div class="title-text">{{ uploadResult }}</div>
                              <div class="copy-area" @click.stop="copyUploadResult">
                                <div class="drop-down">
                                  <span>复制内容</span>
                                </div>
                                <img alt="" src="../../assets/images/e0a71806478e.png"/>
                              </div>
                            </div>
                          </div>
                          <div class="deqr-action-btns-wrapper">
                            <div class="deqr-button-go-home">
                              <div class="drop-down">
                                <span>美化标签、下载其他格式等</span>
                              </div>
                              <span @click.stop="goToHome">前往首页生码</span>
                            </div>
                            <div class="deqr-again-button" @click.stop="decodeAgain">继续解码</div>
                          </div>
                        </div>
                        <img alt="" src="../../assets/images/54520b9b9be9.png" v-show="showInitialUpload"/>
                        <div class="upload-dropzone-desc-wrapper" v-show="showInitialUpload">
                          <h2 style="font-size: 16px;font-weight: 400;">上传图片解码</h2>
                          <h3 style="font-size: 12px;font-weight: 400;">支持拖拽、粘贴图片上传，支持批量解码</h3>
                          <!-- 浮动提示文字 -->
                          <div class="upload-status-float" v-if="showUploadingStatus">
                            正在解码...
                          </div>
                          <div class="upload-error-float" v-if="showUploadError">
                            <ExclamationCircleOutlined style="color: #faad14"/>
                            <span class="error-text">无法识别出该图片中的二维码内容</span>
                          </div>
                        </div>
                        <div class="upload-dropzone-footer-wrapper" v-show="showInitialUpload">
                          <div class="upload-dropzone-footer"></div>
                        </div>
                      </div>
                      <input
                        accept="image/*"
                        id="deqr-uploadBtn"
                        multiple
                        title=""
                        type="file"
                        @change="handleImageUpload"
                        @click.stop
                        ref="uploadInput"
                      />
                    </div>
                  </div>
                </div>

                <!-- URL decoder -->
                <div>
                  <div class="__type-url-content deqr-item">
                    <div class="upload-dropzone-result-wrapper" :style="{display: urlResult ? 'block' : 'none'}">
                      <div class="result-wrapper">
                        <p class="deqr-success-title" style="color: rgba(0, 0, 0, 0.65)">解码结果</p>
                        <div class="text-wrapper">
                          <div class="title-text">{{ urlResult }}</div>
                          <div class="copy-area" @click="copyUrlResult">
                            <div class="drop-down">
                              <span>复制内容</span>
                            </div>
                            <img alt="" src="../../assets/images/e0a71806478e.png"/>
                          </div>
                        </div>
                      </div>
                      <div class="deqr-action-btns-wrapper">
                        <div class="deqr-button-go-home">
                          <div class="drop-down">
                            <span>美化标签、下载其他格式等</span>
                          </div>
                          <span @click.stop="goToHome">前往首页生码</span>
                        </div>
                        <div class="deqr-again-button" @click="decodeAgain">继续解码</div>
                      </div>
                    </div>
                    <div class="deqr-box deqr-box-url">
                      <div class="input-button-wrapper">
                        <div class="input">
                          <input name="deqr" type="hidden" value="deqr"/>
                          <textarea
                            id="deqr_urls"
                            name="deqr_url_input"
                            @dragenter.prevent
                            placeholder="输入二维码图片网址"
                            type="text"
                            v-model="urlInput"
                          ></textarea>
                        </div>
                        <div class="decode-btn" id="deqr_url_btn" @click="decodeUrl">
                          解码
                        </div>
                        <div class="deqr-url-tips-footer"></div>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </div>

            <!-- Drag placeholders -->
            <div class="dragin-placeholder">
              <div class="dragin-wrapper">
                <img alt="" src="../../assets/images/68327ce6118d.png"/>
                <p>图片拖到此处</p>
              </div>
            </div>
            <div class="dragin-placeholder-active">
              <div class="dragin-active-wrapper">
                <img alt="" src="../../assets/images/f09aeccf08dd.png"/>
                <p>松开解码</p>
              </div>
            </div>
          </div>
        </div>

        <!-- Loading and prompt -->
        <div class="deqr_loading">
          <a class="deqr_loading_img" href="deqr.html" title="正在识别二维码"></a>
        </div>
        <div class="deqr_prompt">
          <p class="prompt_current">{{ promptMessage }}</p>
        </div>

        <!-- Result dialog -->
        <div class="deqr-result none" id="deqr_result">
          <div class="copy-success-tip">复制成功</div>
          <div class="result-title">解码结果</div>
          <div class="result-content">
            <p class="result" id="deqrresult">{{ decodeResult }}</p>
            <div class="operate">
              <span class="copy" @click="copyResult">复制</span>
              <span class="generate" @click="generateQR">生成二维码</span>
            </div>
            <input id="uploaddeqr" type="hidden"/>
          </div>
        </div>
      </div>

      <!-- Result dialog modal -->
      <div class="resultdialog dno" id="resultdialog">
        <div class="resultmsg">
          <table>
            <tr>
              <td id="resultmsg">{{ resultMessage }}</td>
            </tr>
          </table>
        </div>
        <div class="resultbtn">
          <a class="btn" id="cameracontinue" @click="continueScan">继续扫描</a>
          <textarea cols="50" id="fe_text" rows="3" style="display:none" v-model="resultText"></textarea>
          <a class="btn" id="cameracopy" @click="copyResultText">复制</a>
          <a class="btn" id="savetext" @click="closeResultDialog">关闭</a>
        </div>
      </div>
    </div>

    <!-- Footer info -->
    <div class="text-center text-grey deqr-footer-info" style="font-size: 12px;">
      <p>
        网页图片右键解码请安装
        <a class="text-blue link" href="help/53255.html" target="_blank">浏览器插件</a>
        ，手机端连续扫码可微信小程序搜索
        <a class="text-blue link" href="//scanbot.cli.im/" target="_blank">扫码机器人</a>
      </p>
    </div>

    <div class="deqr-body-container"></div>

    <!-- Modals -->
    <!-- Delete confirmation modal -->
    <div class="confirmDeleteModal" :style="{display: showDeleteModal ? 'block' : 'none'}">
      <div class="confirmDeleteModalWrapper">
        <div class="title">确定要删除此二维码？</div>
        <div class="desc">删除后将无法恢复</div>
        <div class="btnWrapper">
          <button class="delete-cancelBtn" @click="cancelDelete">取消</button>
          <button class="delete-confirmBtn" @click="confirmDelete">确认删除</button>
        </div>
        <div class="closeIcon" @click="closeDeleteModal">
          <img alt="" src="../../assets/images/838f5f568857.png"/>
        </div>
      </div>
    </div>

    <!-- Empty confirmation modal -->
    <div class="confirmEmptyModal" :style="{display: showEmptyModal ? 'block' : 'none'}">
      <div class="confirmEmptyModalWrapper">
        <div class="title">确定要清空解码列表？</div>
        <div class="desc">清空后将无法恢复</div>
        <div class="btnWrapper">
          <button class="empty-cancelBtn" @click="cancelEmpty">取消</button>
          <button class="empty-confirmBtn" @click="confirmEmpty">确认清空</button>
        </div>
        <div class="closeIcon" @click="closeEmptyModal">
          <img alt="" src="../../assets/images/838f5f568857.png"/>
        </div>
      </div>
    </div>

    <!-- Scan settings modal -->
    <div class="scanSettingModal" :style="{display: showScanSettingModal ? 'block' : 'none'}">
      <div class="scanSettingModalWrapper" style="position: absolute !important; top: 40% !important; left: 50% !important; transform: translate(-50%, -50%) !important; bottom: auto !important; margin: 0 !important;">
        <div class="header">
          <div class="title">摄像头解码设置</div>
          <div class="img-wrapper" @click="closeScanSettingModal">
            <img alt="" src="../../assets/images/838f5f568857.png"/>
          </div>
        </div>
        <div class="headerTextWrapper">
          <div>顶部提示文字：</div>
          <input placeholder="不填则不显示" type="text" v-model="headerText"/>
        </div>
        <div class="bottomTextWrapper">
          <div>底部提示文字：</div>
          <input placeholder="不填则不显示" type="text" v-model="bottomText"/>
        </div>
        <div class="autoOpenWrapper">
          <div>自动打开摄像头：</div>
          <div class="switch-wrapper">
            <label class="switch">
              <input
                :checked="autoOpenCamera"
                id="scan-switch-input-autoOpen"
                type="checkbox"
                @change="toggleAutoOpenCamera"
              />
              <span class="slider"></span>
            </label>
          </div>
        </div>
        <div class="scanSoundWrapper">
          <div>扫码提示音：</div>
          <div class="switch-wrapper">
            <label class="switch">
              <input
                :checked="scanSoundEnabled"
                id="scan-switch-input-scanSound"
                type="checkbox"
                @change="toggleScanSound"
              />
              <span class="slider"></span>
            </label>
          </div>
        </div>
        <div class="autoScanContentWrapper">
          <div class="autoScanWrapper">
            <div>连续扫码模式：</div>
            <div class="switch-wrapper">
              <label class="switch">
                <input
                  :checked="autoScanEnabled"
                  id="scan-switch-input-autoScan"
                  type="checkbox"
                  @change="toggleAutoScan"
                />
                <span class="slider"></span>
              </label>
            </div>
          </div>
          <div class="scanGapWrapper">
            <div>间隔</div>
            <div class="select-placeholder" @click="toggleGapDropdown">
              <span class="text-area">{{ scanGap }}</span>
              <span class="icon-area"></span>
            </div>
            <div class="second-text">秒</div>
            <div class="select-dropdown" :style="{display: showGapDropdown ? 'block' : 'none'}">
              <ul>
                <li @click="selectGap('0.1')">0.1</li>
                <li @click="selectGap('0.5')">0.5</li>
                <li @click="selectGap('1.0')">1.0</li>
                <li @click="selectGap('1.5')">1.5</li>
                <li @click="selectGap('2.0')">2.0</li>
                <li @click="selectGap('2.5')">2.5</li>
                <li @click="selectGap('3.0')">3.0</li>
              </ul>
            </div>
          </div>
        </div>
        <div class="btnWrapper">
          <div class="cancelBtn" @click="closeScanSettingModal">取消</div>
          <div class="confirmBtn" @click="confirmScanSettings">确认</div>
        </div>
      </div>
    </div>

    <!-- Export settings modal -->
    <div class="exportSettingModal" :style="{display: showExportSettingModal ? 'block' : 'none'}">
      <div class="exportSettingModalWrapper" style="position: absolute !important; top: 40% !important; left: 50% !important; transform: translate(-50%, -50%) !important; bottom: auto !important; margin: 0 !important;">
        <div class="header">
          <div class="title">摄像头解码设置</div>
          <div class="img-wrapper" @click="closeExportSettingModal">
            <img alt="" src="../../assets/images/838f5f568857.png"/>
          </div>
        </div>
        <div class="exportFileNameWrapper">
          <div>导出的文件名称：</div>
          <input placeholder="请输入导出的文件名称" type="text" v-model="exportFileName"/>
        </div>
        <div class="exportFileTypeWrapper">
          <div>导出的文件类型：</div>
          <div class="radio-group">
            <label class="radio">
              <input name="exportFileType" type="radio" value="xlsx" v-model="exportFileType"/>
              Excel文件
            </label>
            <label class="radio">
              <input name="exportFileType" type="radio" value="csv" v-model="exportFileType"/>
              csv文件
            </label>
            <label class="radio">
              <input name="exportFileType" type="radio" value="txt" v-model="exportFileType"/>
              txt文件
            </label>
          </div>
        </div>
        <div class="exportDuringWrapper">
          <div>导出的时间范围：</div>
          <div class="radio-group">
            <label class="radio">
              <input name="exportDuring" type="radio" value="today" v-model="exportDuring"/>
              今天
            </label>
            <label class="radio">
              <input name="exportDuring" type="radio" value="all" v-model="exportDuring"/>
              全部数据
            </label>
          </div>
        </div>
        <div class="exportSettingBottomWrapper">
          <div class="exportSettingBottomLeft"></div>
          <div class="exportSettingBottomRight">
            <div class="cancelBtn" @click="closeExportSettingModal">取消</div>
            <div class="confirmBtn" @click="confirmExportSettings">确认</div>
          </div>
        </div>
      </div>
    </div>

    <!-- HTML Scan Modal -->
    <div
      aria-labelledby="myModalLabel"
      class="modal fade"
      id="htmlScanModal"
      role="dialog"
      tabindex="-1"
      :style="{display: showHtmlScanModal ? 'block' : 'none'}"
    >
      <div class="modal-dialog" role="document">
        <div class="modal-content" style="width: 650px;">
          <div class="modal-header">
            <button
              aria-label="Close"
              class="close"
              type="button"
              @click="closeHtmlScanModal"
            >
              <span aria-hidden="true">×</span>
            </button>
            <h4 class="modal-title" id="myModalLabel">二维码扫描</h4>
          </div>
          <div class="modal-body">
            <div class="scanner">
              <div class="scan-area">
                <div class="mark top-left"></div>
                <div class="mark top-right"></div>
                <div class="mark bottom-left"></div>
                <div class="mark bottom-right"></div>
              </div>
              <video
                id="scanVideo"
                ref="htmlScanVideo"
              ></video>
            </div>
            <div id="scan-content"></div>
          </div>
          <div class="modal-footer">
            <button class="btn btn-default btn-sm" id="copyResultBtn" type="button" @click="copyModalResult">复制</button>
            <button class="btn btn-default btn-sm" id="continueToScan" type="button" @click="continueModalScan">继续扫码</button>
          </div>
        </div>
      </div>
    </div>

    <!-- Result wrap -->
    <div class="result-wrap none">
      <div class="decode-result">
        <div class="close-btn" @click="closeResult">×</div>
        <div class="title">解码结果</div>
        <div class="result-outer">
          <div class="result">{{ modalResult }}</div>
        </div>
        <div class="operate">
          <button class="op-generate btn" @click="generateFromResult">生成二维码</button>
          <button class="op-copy btn btn-green" @click="copyModalResult">复制</button>
          <span class="scan-again" @click="scanModalAgain">再次扫描</span>
        </div>
        <div class="tip">
          <i class="clifont anticon-cli-check-fill"></i>
          <span>复制成功</span>
        </div>
      </div>
    </div>

    <!-- QR Style wrapper -->
    <div class="qr-style-wrapper">
      <div class="qr-style-content">
        <div class="close" @click="closeQrStyle">×</div>
        <div class="real-content"></div>
      </div>
    </div>

    <!--
    ============================================
    📑📑📑 中间选项卡区开始 📑📑📑
    这个区域包含功能介绍、最近解码、讨论等选项卡导航
    ============================================
    -->
    <!-- Tab Content Section -->
    <div class="tab-file-box bottom-white-line" style="background-color: #fafafa;">
      <div class="w-1000">
        <div class="nav-fixed-empty"></div>
        <div id="tab-nav">
          <ul class="tab-ul list_tab page-main-content">
            <li
              class="tab-item noMarginLeft"
              :class="{active: currentTab === 'info'}"
              data-id="16291"
              data-name="功能介绍"
              data-tab-id="16291"
              data-tab-item=""
              data-tab-path="info"
              data-tab-type="blog"
              data-tab-url="/deqr"
              data-type="解码"
              @click="switchTab('info')"
            >
              <a href="deqr.html" rel="canonical" title="功能介绍">功能介绍</a>
            </li>
            <li
              class="tab-item"
              :class="{active: currentTab === 'other'}"
              data-id="16270"
              data-name="最近解码"
              data-tab-id="16270"
              data-tab-item=""
              data-tab-path="other"
              data-tab-type="tp_view"
              data-tab-url="/deqr/other"
              data-type="解码"
              @click="switchTab('other')"
            >
              <a href="deqr/other.html" rel="canonical" title="最近解码">最近解码</a>
            </li>
            <li
              class="tab-item"
              :class="{active: currentTab === 'comment'}"
              data-id="11908"
              data-name="讨论"
              data-tab-id="11908"
              data-tab-item=""
              data-tab-path="comment"
              data-tab-type="comment"
              data-tab-url="/deqr/comment"
              data-type="解码"
              @click="switchTab('comment')"
            >
              <a href="deqr/comment.html" id="comment-tab-item" rel="canonical" title="讨论">讨论(75)</a>
            </li>
          </ul>
        </div>
      </div>
    </div>
    <!--
    ============================================
    📑📑📑 中间选项卡区结束 📑📑📑
    ============================================
    -->

    <div id="new-blog-container"></div>

    <!--
    ============================================
    📄📄📄 下方tab区开始 📄📄📄
    这个区域包含选项卡对应的内容：功能介绍文档、最近解码记录、用户讨论等
    ============================================
    -->
    <!-- Tab content -->
    <div class="w-p100 p-b-lg tab-deqr-box white tab-content-container">
      <div class="page-main-content white">
        <div class="article-tab-box clearfix" id="article">
          <div class="wordpress-article">
            <div class="wiki wordpress-article-box doc-content inline" id="wordpress_article_box">
              <div class="wait-now" id="wait_now" style="display: none;">
                <img alt="loading" src="../../assets/images/cbd0851f409c.gif"/>
              </div>
              <div class="wordpress_article_info_box entry-content" id="wordpress_article_info_box">
                <p>只需上传二维码图片或使用摄像头扫描，即可免费快速提取二维码中的网址、文本等信息，实现二维码转链接。适用于例如资产管理、出入库登记等多种场景。</p>
                <h2>一、核心功能</h2>
                <h3>1. 不限量免费使用</h3>
                <p>无需支付任何费用，解码服务永久免费，无次数和数量限制，适合长期使用。</p>
                <h3>2. 多种解码方式</h3>
                <ul>
                  <li><strong>上传图片解码</strong>：直接上传本地二维码图片，快速提取其中的信息。</li>
                  <li><strong>输入图片URL解码</strong>：输入在线二维码图片的URL，进行信息提取，无需下载图片。</li>
                  <li><strong>电脑摄像头实时扫描</strong>：利用电脑摄像头实时扫描二维码，实现即时解码，更方便。</li>
                </ul>
                <h3>3. 批量解码</h3>
                <p>一次解一批码，快速完成大量二维码的信息提取，显著提高工作效率。</p>
                <h3>4. 解码记录结果导出</h3>
                <p>提供将解码结果批量导出为Excel、CSV、TXT等多种格式，便于后续的数据统计、分析和归档。</p>
                <p><img alt="" data-height="1182" data-width="1872" src="../../assets/images/e09ddb19a9ec.png"/></p>
                <h2>二、更多实用工具</h2>
                <h3>1. 扫码机器人</h3>
                <p>提供扫码机器人小程序，将手机转变为高效"扫码枪"，支持快速连续扫描，适用于大规模二维码处理需求。<a href="scene/2773.html" title="了解更多">了解更多</a></p>
                <h3>2. 浏览器插件</h3>
                <p>提供专用浏览器插件，用户可在任意网页中通过点击插件或使用右键菜单快速解码二维码，操作简便快捷。<a href="help/53255.html" title="安装插件">安装插件</a></p>
                <h2>三、常见问题</h2>
                <h3>1. 微信二维码解码出来的网址，为什么扫码后是下载微信页面？</h3>
                <p>由于微信域名（如 <a href="http://weixin.qq.com/r/">http://weixin.qq.com/r/</a>... ）受到微信生态的特殊限制，若在其他浏览器中打开该链接，会默认跳转至微信下载页面。只有通过"微信扫一扫"功能，才能正常访问相应内容。</p>
              </div>
            </div>
            <div class="wikiOutlineWrapper" ref="outlineWrapper">
              <ul class="wikiOutlineContainer" ref="outlineContainer">
                <li v-for="(item, index) in outlineItems"
                    :key="index"
                    :class="['item', { active: activeOutlineIndex === index }]"
                    :data-target-header="item.tagName"
                    @click="scrollToHeader(item, index)">
                  <span>{{ item.text }}</span>
                </li>
              </ul>
            </div>
          </div>
        </div>
      </div>
    </div>
    <!--
    ============================================
    📄📄📄 下方tab区结束 📄📄📄
    ============================================
    -->

    <!-- Comment modal -->
    <div class="modal fade" data-backdrop="static" id="modal-alert-comment-box">
      <div class="modal-dialog">
        <div class="modal-content">
          <div class="modal-header" style="padding:15px 15px;border-bottom: none;">
            <button class="close" id="comment-close-button" style="position: absolute;right: 15px;top: 15px;" type="button" @click="closeCommentModal">
              <span aria-hidden="true">×</span>
              <span class="sr-only">Close</span>
            </button>
            <h4 class="modal-title"></h4>
          </div>
          <div class="modal-body p-x-md" style="padding-top:0px;padding-bottom:0px;">
            <div id="comment-box"></div>
            <div class="feedback-item clearfix feedback-box">
              <div class="feedback-label">回复方式</div>
              <div class="feedback-content feedback-content-500">
                <div>
                  <label class="radio-inline">
                    <input id="receiveWechat" name="receiveMethodModal" type="radio" value="wechat" v-model="receiveMethod"/> 微信快捷接收（推荐）
                  </label>
                  <label class="radio-inline">
                    <input id="receiveEmail" name="receiveMethodModal" type="radio" value="email" v-model="receiveMethod"/> 邮箱接收
                  </label>
                </div>
                <div class="none m-t" id="email-area" :class="{none: receiveMethod !== 'email'}">
                  <input class="form-control text-xs" id="email" name="email" placeholder="我们将以邮件形式答复你" type="text" v-model="userEmail"/>
                </div>
                <div class="none m-t text-darkgrey" id="wechat-area" :class="{none: receiveMethod !== 'wechat'}">
                  <img alt="" class="m-r" id="wechat-qr" :src="wechatQrUrl"/>
                  <div class="logo-in-qrcode">
                    <img alt="loading" src="../../assets/images/28ae6fb6d9ad.png"/>
                  </div>
                  <div class="scan-success none" :class="{none: !wechatScanned}">
                    <i class="fa fa-check text-green"></i> 已关注
                  </div>
                </div>
              </div>
            </div>
          </div>
          <div class="modal-footer" style="border-top: none;">
            <span class="m-l text-danger none" id="error-message">{{ errorMessage }}</span>
            <button class="btn btn-outline b-green text-green" id="publish-cancel-btn" style="margin-bottom: 0;margin-left: 5px;height: 28px;font-size: 12px;line-height: 11px;width:72px;" @click="cancelComment">取消</button>
            <button class="btn green" id="publish-submit-btn" style="margin-bottom: 0;margin-left: 5px;height: 28px;font-size: 12px;line-height: 12px;width:72px;" @click="submitComment">提交</button>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted, nextTick } from 'vue'
import { useRouter } from 'vue-router'
import { ExclamationCircleOutlined } from '@ant-design/icons-vue'

// Router instance
const router = useRouter()

// Component state
const showScanner = ref(false)
const scanTimeNumber = ref(0)
const scanResult = ref('')
const scanGap = ref('0.5')
const scannerHeaderText = ref('')
const scannerBottomText = ref('')
const uploadResult = ref('')
const urlResult = ref('')
const urlInput = ref('')
const promptMessage = ref('')
const decodeResult = ref('')
const resultMessage = ref('')
const resultText = ref('')
const modalResult = ref('')
const currentTab = ref('info')

// Outline navigation state
const outlineItems = ref<Array<{ text: string, tagName: string, element: HTMLElement }>>([])
const activeOutlineIndex = ref(-1)
const isScrolling = ref(false)
const outlineWrapper = ref<HTMLElement | null>(null)
const outlineContainer = ref<HTMLElement | null>(null)

// Loading and processing states
const isUploading = ref(false)
const isProcessing = ref(false)
const isDragOver = ref(false)
const processingFiles = ref<string[]>([])
const uploadError = ref('')
const showUploadingStatus = ref(false)
const showUploadError = ref(false)

// Modal states
const showDeleteModal = ref(false)
const showEmptyModal = ref(false)
const showScanSettingModal = ref(false)
const showExportSettingModal = ref(false)
const showHtmlScanModal = ref(false)
const showGapDropdown = ref(false)

// Settings
const headerText = ref('')
const bottomText = ref('')
const autoOpenCamera = ref(true)
const scanSoundEnabled = ref(true)
const autoScanEnabled = ref(false)
const exportFileName = ref('')
const exportFileType = ref('xlsx')
const exportDuring = ref('today')

// Comment modal
const receiveMethod = ref('wechat')
const userEmail = ref('')
const wechatQrUrl = ref('')
const wechatScanned = ref(false)
const errorMessage = ref('')

// Refs
const scanVideo = ref<HTMLVideoElement>()
const htmlScanVideo = ref<HTMLVideoElement>()
const uploadInput = ref<HTMLInputElement>()
const testVideo = ref<HTMLVideoElement>()

// Camera state
const cameraStream = ref<MediaStream | null>(null)
const isScanning = ref(false)
const scanInterval = ref<number | null>(null)

// Computed properties for display control
const showUploadResult = computed(() => {
  return !!uploadResult.value && uploadResult.value.trim() !== ''
})

const showInitialUpload = computed(() => {
  return !showUploadResult.value
})

// Load jsQR library dynamically with multiple fallbacks
let jsQRLibrary: any = null
let jsQRLoadPromise: Promise<any> | null = null
let jsQRLoadAttempts = 0
const MAX_LOAD_ATTEMPTS = 3

const loadJsQRLibrary = async (): Promise<any> => {
  // Return cached library
  if (jsQRLibrary) {
    return jsQRLibrary
  }

  // Return ongoing load promise
  if (jsQRLoadPromise) {
    return jsQRLoadPromise
  }

  // Check if already loaded globally
  if ((window as any).jsQR) {
    jsQRLibrary = (window as any).jsQR
    console.log('jsQR library found in global scope')
    return jsQRLibrary
  }

  // Start loading
  jsQRLoadPromise = (async () => {
    jsQRLoadAttempts++
    console.log(`Loading jsQR library, attempt ${jsQRLoadAttempts}/${MAX_LOAD_ATTEMPTS}`)

    const cdnUrls = [
      'https://cdn.jsdelivr.net/npm/jsqr@1.4.0/dist/jsQR.js',
      'https://unpkg.com/jsqr@1.4.0/dist/jsQR.js',
      'https://cdnjs.cloudflare.com/ajax/libs/jsQR/1.4.0/jsQR.min.js',
      'https://cdn.bootcdn.net/ajax/libs/jsQR/1.4.0/jsQR.min.js'
    ]

    for (const url of cdnUrls) {
      try {
        console.log(`Trying to load jsQR from: ${url}`)

        await new Promise((resolve, reject) => {
          // Remove existing script with same src
          const existingScript = document.querySelector(`script[src="${url}"]`)
          if (existingScript) {
            existingScript.remove()
          }

          const script = document.createElement('script')
          script.src = url
          script.onload = () => {
            console.log(`✓ jsQR successfully loaded from: ${url}`)
            resolve((window as any).jsQR)
          }
          script.onerror = () => {
            console.warn(`✗ Failed to load jsQR from ${url}`)
            reject(new Error(`Failed to load jsQR from ${url}`))
          }

          // Add timeout for loading
          setTimeout(() => {
            reject(new Error(`Timeout loading jsQR from ${url}`))
          }, 10000)

          document.head.appendChild(script)
        })

        if ((window as any).jsQR) {
          jsQRLibrary = (window as any).jsQR
          jsQRLoadPromise = null
          console.log('jsQR library successfully initialized')
          return jsQRLibrary
        }
      } catch (error) {
        console.warn(`Failed to load jsQR from ${url}:`, error)
        continue
      }
    }

    jsQRLoadPromise = null

    if (jsQRLoadAttempts < MAX_LOAD_ATTEMPTS) {
      console.log(`All CDN sources failed, retrying... (${jsQRLoadAttempts}/${MAX_LOAD_ATTEMPTS})`)
      // Recursive retry after delay
      await new Promise(resolve => setTimeout(resolve, 2000))
      return loadJsQRLibrary()
    } else {
      throw new Error(`Failed to load jsQR library after ${MAX_LOAD_ATTEMPTS} attempts`)
    }
  })()

  return jsQRLoadPromise
}

// 图像预处理函数：提高二维码识别成功率
const preprocessCanvas = (canvas: HTMLCanvasElement): HTMLCanvasElement[] => {
  const ctx = canvas.getContext('2d')
  if (!ctx) return [canvas]

  const results: HTMLCanvasElement[] = []

  // 原始图像
  results.push(canvas)

  // 增强对比度
  try {
    const enhancedCanvas = document.createElement('canvas')
    enhancedCanvas.width = canvas.width
    enhancedCanvas.height = canvas.height
    const enhancedCtx = enhancedCanvas.getContext('2d')!

    enhancedCtx.filter = 'contrast(150%) brightness(110%)'
    enhancedCtx.drawImage(canvas, 0, 0)
    results.push(enhancedCanvas)
  } catch (error) {
    console.warn('Enhanced contrast processing failed:', error)
  }

  // 灰度化处理
  try {
    const grayscaleCanvas = document.createElement('canvas')
    grayscaleCanvas.width = canvas.width
    grayscaleCanvas.height = canvas.height
    const grayscaleCtx = grayscaleCanvas.getContext('2d')!

    grayscaleCtx.filter = 'grayscale(100%) contrast(150%)'
    grayscaleCtx.drawImage(canvas, 0, 0)
    results.push(grayscaleCanvas)
  } catch (error) {
    console.warn('Grayscale processing failed:', error)
  }

  return results
}

// QR Code decoding function using jsQR library with enhanced algorithms
const decodeQRFromCanvas = async (canvas: HTMLCanvasElement): Promise<string | null> => {
  try {
    // Load jsQR library
    const jsQR = await loadJsQRLibrary()
    if (!jsQR) {
      throw new Error('jsQR library not available')
    }

    // 预处理图像以提高识别成功率
    const processedCanvases = preprocessCanvas(canvas)

    // 多种识别策略
    const strategies = [
      { inversionAttempts: "dontInvert" },
      { inversionAttempts: "onlyInvert" },
      { inversionAttempts: "attemptBoth" }
    ]

    // 对每个预处理后的图像尝试所有策略
    for (const processedCanvas of processedCanvases) {
      const ctx = processedCanvas.getContext('2d')
      if (!ctx) continue

      try {
        const imageData = ctx.getImageData(0, 0, processedCanvas.width, processedCanvas.height)

        for (const options of strategies) {
          try {
            const code = jsQR(imageData.data, imageData.width, imageData.height, options)
            if (code && code.data && code.data.trim()) {
              console.log('✓ QR Code detected:', code.data)
              console.log('Detection details:', {
                location: code.location,
                version: code.version,
                errorCorrectionLevel: code.errorCorrectionLevel,
                strategy: options
              })
              return code.data.trim()
            }
          } catch (strategyError) {
            // 静默处理策略错误，继续尝试下一个
            continue
          }
        }
      } catch (imageError) {
        console.warn('Image processing error:', imageError)
        continue
      }
    }

    return null
  } catch (error) {
    console.error('QR decode error:', error)
    return null
  }
}

// Create canvas from image file
const createCanvasFromImage = (file: File): Promise<HTMLCanvasElement> => {
  return new Promise((resolve, reject) => {
    const img = new Image()
    const canvas = document.createElement('canvas')
    const ctx = canvas.getContext('2d')

    if (!ctx) {
      reject(new Error('无法创建canvas上下文'))
      return
    }

    img.onload = () => {
      canvas.width = img.width
      canvas.height = img.height
      ctx.drawImage(img, 0, 0)
      resolve(canvas)
    }

    img.onerror = () => reject(new Error('图片加载失败'))

    const reader = new FileReader()
    reader.onload = (e) => {
      img.src = e.target?.result as string
    }
    reader.onerror = () => reject(new Error('文件读取失败'))
    reader.readAsDataURL(file)
  })
}

// Process single file for QR code detection
const processFile = async (file: File): Promise<{ success: boolean; result?: string; error?: string }> => {
  try {
    // Validate file type
    if (!file.type.startsWith('image/')) {
      return { success: false, error: '请选择图片文件' }
    }

    // Validate file size (max 10MB)
    const maxSize = 10 * 1024 * 1024
    if (file.size > maxSize) {
      return { success: false, error: '图片大小不能超过10MB' }
    }

    // Create canvas and decode
    const canvas = await createCanvasFromImage(file)
    const decodedContent = await decodeQRFromCanvas(canvas)

    if (decodedContent) {
      return { success: true, result: decodedContent }
    } else {
      return { success: false, error: '未检测到二维码，请确保图片清晰且包含有效二维码' }
    }
  } catch (error) {
    return {
      success: false,
      error: error instanceof Error ? error.message : '处理文件时发生未知错误'
    }
  }
}

// Process multiple files
const processFiles = async (files: FileList | File[]) => {
  const fileArray = Array.from(files)

  if (fileArray.length === 0) return

  isProcessing.value = true
  uploadError.value = ''
  processingFiles.value = fileArray.map(f => f.name)
  showUploadingStatus.value = true
  showUploadError.value = false

  try {
    // Process first file (for single file result)
    const result = await processFile(fileArray[0])

    if (result.success && result.result) {
      uploadResult.value = result.result
      promptMessage.value = `成功解码 ${fileArray.length} 个文件`
      showUploadingStatus.value = false
      showUploadError.value = false

      // Show success state
      showUploadSuccess()
    } else {
      uploadError.value = result.error || '解码失败'
      promptMessage.value = '解码失败'
      showUploadingStatus.value = false
      showUploadError.value = true

      // Show error state - 不直接alert，而是通过浮动提示显示
      // showUploadError(result.error || '解码失败')

      // 3秒后自动隐藏错误提示
      setTimeout(() => {
        showUploadError.value = false
      }, 3000)
    }
  } catch (error) {
    const errorMsg = error instanceof Error ? error.message : '处理失败'
    uploadError.value = errorMsg
    showUploadingStatus.value = false
    showUploadError.value = true
    
    // 3秒后自动隐藏错误提示
    setTimeout(() => {
      showUploadError.value = false
    }, 3000)
  } finally {
    isProcessing.value = false
    processingFiles.value = []
    showUploadingStatus.value = false
  }
}

// Show upload success state
const showUploadSuccess = () => {
  // Update UI state to show result - 只操作上传区域，避免影响摄像头区域
  setTimeout(() => {
    const uploadContainer = document.querySelector('.upload-container')
    const resultWrapper = uploadContainer?.querySelector('.upload-dropzone-result-wrapper') as HTMLElement
    const titleText = uploadContainer?.querySelector('.upload-dropzone-result-wrapper .title-text') as HTMLElement

    if (resultWrapper && titleText) {
      titleText.textContent = uploadResult.value
      resultWrapper.style.display = 'block'
    }
  }, 100)
}

// Show upload error state (已改为通过浮动提示显示，保留函数以防其他地方调用)
const showUploadErrorLegacy = (error: string) => {
  // Show error message
  setTimeout(() => {
    alert(`解码失败: ${error}`)
  }, 100)
}

// Component methods
const handleFileUpload = async (event: Event) => {
  const target = event.target as HTMLInputElement
  const files = target.files

  if (files && files.length > 0) {
    await processFiles(files)
  }
  
  // 重要：处理完成后清空input的值，确保下次选择相同文件时也能触发change事件
  target.value = ''
}

const handleImageUpload = async (event: Event) => {
  const target = event.target as HTMLInputElement
  const files = target.files

  if (files && files.length > 0) {
    await processFiles(files)
  }
  
  // 重要：处理完成后清空input的值，确保下次选择相同文件时也能触发change事件
  target.value = ''
}

const handleDrop = async (event: DragEvent) => {
  event.preventDefault()
  isDragOver.value = false

  const files = event.dataTransfer?.files
  if (files && files.length > 0) {
    await processFiles(files)
  }
}

// Drag and drop handlers
const handleDragEnter = (event: DragEvent) => {
  event.preventDefault()
  isDragOver.value = true
}

const handleDragLeave = (event: DragEvent) => {
  event.preventDefault()
  // Only set to false if we're leaving the drop zone completely
  const rect = (event.currentTarget as HTMLElement).getBoundingClientRect()
  const x = event.clientX
  const y = event.clientY

  if (x < rect.left || x >= rect.right || y < rect.top || y >= rect.bottom) {
    isDragOver.value = false
  }
}

const handleDragOver = (event: DragEvent) => {
  event.preventDefault()
}

// Handle dropzone click - only trigger file upload when no result is shown
const handleDropzoneClick = () => {
  // 只有在没有显示结果时才触发文件上传
  if (!showUploadResult.value) {
    triggerFileUpload()
  }
  // 如果正在显示结果，点击背景不做任何操作
}

// Trigger file upload
const triggerFileUpload = () => {
  if (uploadInput.value) {
    // 先清空input的值，确保每次都能触发change事件
    uploadInput.value.value = ''
    uploadInput.value.click()
  }
}

const openScannerSettings = () => {
  showScanSettingModal.value = true
}

const closeScanSettingModal = () => {
  showScanSettingModal.value = false
}

const confirmScanSettings = () => {
  scannerHeaderText.value = headerText.value
  scannerBottomText.value = bottomText.value
  closeScanSettingModal()
}

const toggleAutoOpenCamera = () => {
  autoOpenCamera.value = !autoOpenCamera.value
}

const toggleScanSound = () => {
  scanSoundEnabled.value = !scanSoundEnabled.value
}

const toggleAutoScan = () => {
  autoScanEnabled.value = !autoScanEnabled.value
}

const toggleGapDropdown = () => {
  showGapDropdown.value = !showGapDropdown.value
}

const selectGap = (gap: string) => {
  scanGap.value = gap
  showGapDropdown.value = false
}

const decodeUrl = async () => {
  if (!urlInput.value.trim()) {
    alert('请输入二维码图片网址')
    return
  }

  try {
    // Show loading state
    promptMessage.value = '正在获取网址图片...'

    // Create image element to load the URL
    const img = new Image()
    img.crossOrigin = 'anonymous' // Try to handle CORS

    const loadPromise = new Promise<HTMLImageElement>((resolve, reject) => {
      img.onload = () => resolve(img)
      img.onerror = () => reject(new Error('无法加载图片，请检查网址是否正确'))
    })

    img.src = urlInput.value

    // Wait for image to load
    const loadedImg = await loadPromise

    // Create canvas and decode
    const canvas = document.createElement('canvas')
    const ctx = canvas.getContext('2d')

    if (!ctx) {
      throw new Error('无法创建画布')
    }

    canvas.width = loadedImg.width
    canvas.height = loadedImg.height
    ctx.drawImage(loadedImg, 0, 0)

    promptMessage.value = '正在解码...'

    // Decode QR code
    const decodedContent = await decodeQRFromCanvas(canvas)

    if (decodedContent) {
      urlResult.value = decodedContent
      promptMessage.value = '解码成功'
    } else {
      throw new Error('未检测到二维码内容')
    }

  } catch (error) {
    const errorMsg = error instanceof Error ? error.message : '解码失败'
    alert(errorMsg)
    promptMessage.value = ''
  }
}

// Camera functions
const startCamera = async (): Promise<void> => {
  try {
    // Stop existing stream if any
    await stopCamera()

    // Request camera access with optimized constraints
    const constraints: MediaStreamConstraints = {
      video: {
        width: { ideal: 1280, max: 1920 },
        height: { ideal: 720, max: 1080 },
        facingMode: { ideal: 'environment', fallback: 'user' }, // 优先使用后置摄像头进行扫描
        frameRate: { ideal: 30 }
      }
    }

    const stream = await navigator.mediaDevices.getUserMedia(constraints)
    cameraStream.value = stream

    // Set video source to test video element
    if (testVideo.value) {
      testVideo.value.srcObject = stream

      // 等待视频元数据加载完成
      await new Promise<void>((resolve) => {
        testVideo.value!.onloadedmetadata = () => {
          testVideo.value!.play().then(() => {
            console.log(`摄像头已启动，分辨率: ${testVideo.value!.videoWidth}x${testVideo.value!.videoHeight}`)
            resolve()
          })
        }
      })

      // 延迟启动扫描以确保视频完全加载
      setTimeout(() => {
        startScanning()
      }, 1000)
    }

    // Also set to original video element if exists
    if (scanVideo.value) {
      scanVideo.value.srcObject = stream
      await scanVideo.value.play()

      // Show scanner UI
      showScanner.value = true
    }

  } catch (error) {
    console.error('Camera access error:', error)

    let errorMessage = '无法访问摄像头'
    if (error instanceof Error) {
      if (error.name === 'NotAllowedError') {
        errorMessage = '请允许访问摄像头权限'
      } else if (error.name === 'NotFoundError') {
        errorMessage = '未找到摄像头设备'
      } else if (error.name === 'NotReadableError') {
        errorMessage = '摄像头正被其他应用占用'
      }
    }

    alert(errorMessage)
    console.error(errorMessage)
  }
}

const stopCamera = async (): Promise<void> => {
  // Stop scanning
  stopScanning()

  // Stop video tracks
  if (cameraStream.value) {
    cameraStream.value.getTracks().forEach(track => track.stop())
    cameraStream.value = null
  }

  // Clear video source
  if (scanVideo.value) {
    scanVideo.value.srcObject = null
  }

  // Hide scanner UI
  showScanner.value = false
}

const startScanning = (): void => {
  if (isScanning.value) return

  isScanning.value = true

  const scanQRCode = async () => {
    if (!isScanning.value) return

    // 优先使用主摄像头视频
    const videoElement = testVideo.value || scanVideo.value
    if (!videoElement) return

    try {
      // 确保视频已加载并具有有效尺寸
      if (videoElement.videoWidth === 0 || videoElement.videoHeight === 0) {
        return
      }

      // Create canvas from video
      const canvas = document.createElement('canvas')
      const ctx = canvas.getContext('2d')

      if (!ctx) return

      canvas.width = videoElement.videoWidth
      canvas.height = videoElement.videoHeight

      // Draw current frame
      ctx.drawImage(videoElement, 0, 0, canvas.width, canvas.height)

      // Decode QR code
      const decodedContent = await decodeQRFromCanvas(canvas)

      if (decodedContent) {
        console.log('QR码扫描成功:', decodedContent)

        // Found QR code
        scanResult.value = decodedContent
        scanTimeNumber.value += 1

        // Play sound if enabled
        if (scanSoundEnabled.value) {
          playBeepSound()
        }

        // Show result
        showScanResult(decodedContent)

        // Continue scanning if auto scan is enabled
        if (autoScanEnabled.value) {
          setTimeout(() => {
            scanResult.value = ''
            // Continue scanning automatically
          }, parseFloat(scanGap.value) * 1000)
        } else {
          // Stop scanning for single scan mode
          stopScanning()
        }
      }

    } catch (error) {
      console.error('Scan error:', error)
    }
  }

  // 更频繁扫描以提高响应性
  scanInterval.value = window.setInterval(scanQRCode, 200)
  console.log('开始QR码扫描...')
}

const stopScanning = (): void => {
  isScanning.value = false

  if (scanInterval.value) {
    clearInterval(scanInterval.value)
    scanInterval.value = null
  }
}

const showScanResult = (result: string): void => {
  // Update result display
  scanResult.value = result

  console.log(`✓ 扫描结果: ${result}`)

  // 分析结果类型
  const resultType = analyzeQRResult(result)
  console.log(`• 结果类型: ${resultType}`)

  // 自动复制到剪贴板
  copyToClipboard(result).then(() => {
    console.log('✓ 扫描结果已自动复制到剪贴板')
    // 显示复制成功提示
    showToast('扫描成功！结果已复制到剪贴板', 'success')
  }).catch(() => {
    showToast('扫描成功！请手动复制结果', 'warning')
  })

  // Show result wrapper
  const resultWrapper = document.querySelector('.scanner-result-wrapper')
  if (resultWrapper) {
    (resultWrapper as HTMLElement).style.display = 'block'
  }

  // 显示成功提示
  const scannerResultOverlay = document.querySelector('.scanner-result-overlay')
  if (scannerResultOverlay) {
    (scannerResultOverlay as HTMLElement).style.display = 'flex'
  }

  // 保存扫描历史
  saveScanHistory(result, resultType)
}

// 分析二维码结果类型
const analyzeQRResult = (result: string): string => {
  if (result.startsWith('http://') || result.startsWith('https://')) {
    return 'URL网址'
  } else if (result.startsWith('tel:')) {
    return '电话号码'
  } else if (result.startsWith('mailto:')) {
    return '电子邮件'
  } else if (result.startsWith('wifi:')) {
    return 'WiFi配置'
  } else if (result.includes('\n') && (result.includes('姓名') || result.includes('电话'))) {
    return '联系人信息'
  } else if (/^\d+$/.test(result)) {
    return '数字'
  } else {
    return '文本内容'
  }
}

// 显示提示消息
const showToast = (message: string, type: 'success' | 'warning' | 'error' = 'success'): void => {
  // 创建toast元素
  const toast = document.createElement('div')
  toast.className = `scan-toast scan-toast-${type}`
  toast.textContent = message

  // 设置样式 - 显示在页面中下方
  Object.assign(toast.style, {
    position: 'fixed',
    bottom: '120px',  // 显示在页面中下方
    left: '50%',
    transform: 'translateX(-50%)',
    backgroundColor: type === 'success' ? '#52c41a' : type === 'warning' ? '#faad14' : '#f5222d',
    color: 'white',
    padding: '12px 20px',
    borderRadius: '6px',
    fontSize: '14px',
    fontWeight: '500',
    boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)',
    zIndex: '10000',
    opacity: '0',
    transition: 'all 0.3s ease',
    maxWidth: '320px',
    textAlign: 'center',
    wordWrap: 'break-word'
  })

  document.body.appendChild(toast)

  // 显示动画 - 从下往上出现
  requestAnimationFrame(() => {
    toast.style.opacity = '1'
    toast.style.transform = 'translateX(-50%) translateY(0)'
  })

  // 自动隐藏 - 向下消失
  setTimeout(() => {
    toast.style.opacity = '0'
    toast.style.transform = 'translateX(-50%) translateY(10px)'
    setTimeout(() => {
      if (document.body.contains(toast)) {
        document.body.removeChild(toast)
      }
    }, 300)
  }, 3000)
}

// 保存扫描历史
const saveScanHistory = (result: string, type: string): void => {
  try {
    const history = JSON.parse(localStorage.getItem('qr-scan-history') || '[]')
    const newEntry = {
      id: Date.now(),
      result,
      type,
      timestamp: new Date().toISOString(),
      date: new Date().toLocaleDateString('zh-CN'),
      time: new Date().toLocaleTimeString('zh-CN')
    }

    history.unshift(newEntry)

    // 只保留最近50条记录
    if (history.length > 50) {
      history.splice(50)
    }

    localStorage.setItem('qr-scan-history', JSON.stringify(history))
    console.log('✓ 扫描记录已保存到本地存储')
  } catch (error) {
    console.warn('保存扫描历史失败:', error)
  }
}

const playBeepSound = (): void => {
  // Create and play beep sound
  try {
    const audioContext = new (window.AudioContext || (window as any).webkitAudioContext)()
    const oscillator = audioContext.createOscillator()
    const gainNode = audioContext.createGain()

    oscillator.connect(gainNode)
    gainNode.connect(audioContext.destination)

    oscillator.frequency.setValueAtTime(800, audioContext.currentTime)
    gainNode.gain.setValueAtTime(0.3, audioContext.currentTime)
    gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.1)

    oscillator.start(audioContext.currentTime)
    oscillator.stop(audioContext.currentTime + 0.1)
  } catch (error) {
    console.warn('Could not play beep sound:', error)
  }
}

const copyScanResult = async () => {
  if (!scanResult.value) {
    showToast('没有可复制的内容', 'warning')
    return
  }

  try {
    await copyToClipboard(scanResult.value)
    showToast('已复制到剪贴板', 'success')
  } catch (error) {
    console.error('Copy failed:', error)
    showToast('复制失败，请手动选择复制', 'error')
  }
}

// Copy functions with user feedback
const showCopySuccess = () => {
  // Show copy success message
  const copyTip = document.querySelector('.copy-success-tip') as HTMLElement
  if (copyTip) {
    copyTip.style.display = 'block'
    copyTip.style.opacity = '1'
    setTimeout(() => {
      copyTip.style.opacity = '0'
      setTimeout(() => {
        copyTip.style.display = 'none'
      }, 200)
    }, 1500)
  }
}

const copyToClipboard = async (text: string) => {
  try {
    await navigator.clipboard.writeText(text)
    showCopySuccess()
    return true
  } catch (err) {
    // Fallback for older browsers
    const textArea = document.createElement('textarea')
    textArea.value = text
    document.body.appendChild(textArea)
    textArea.focus()
    textArea.select()

    try {
      document.execCommand('copy')
      showCopySuccess()
      return true
    } catch (fallbackErr) {
      alert('复制失败，请手动选择复制')
      return false
    } finally {
      document.body.removeChild(textArea)
    }
  }
}

const copyUploadResult = async () => {
  if (!uploadResult.value) {
    showToast('没有可复制的内容', 'warning')
    return
  }
  
  try {
    await navigator.clipboard.writeText(uploadResult.value)
    showToast('复制成功', 'success')
  } catch (error) {
    // Fallback to older method
    const textArea = document.createElement('textarea')
    textArea.value = uploadResult.value
    document.body.appendChild(textArea)
    textArea.focus()
    textArea.select()
    
    try {
      document.execCommand('copy')
      showToast('复制成功', 'success')
    } catch (fallbackError) {
      showToast('复制失败，请手动选择复制', 'error')
    } finally {
      document.body.removeChild(textArea)
    }
  }
}

const copyUrlResult = async () => {
  if (!urlResult.value) {
    showToast('没有可复制的内容', 'warning')
    return
  }
  
  try {
    await navigator.clipboard.writeText(urlResult.value)
    showToast('复制成功', 'success')
  } catch (error) {
    // Fallback to older method
    const textArea = document.createElement('textarea')
    textArea.value = urlResult.value
    document.body.appendChild(textArea)
    textArea.focus()
    textArea.select()
    
    try {
      document.execCommand('copy')
      showToast('复制成功', 'success')
    } catch (fallbackError) {
      showToast('复制失败，请手动选择复制', 'error')
    } finally {
      document.body.removeChild(textArea)
    }
  }
}

const copyResult = async () => {
  if (decodeResult.value) {
    await copyToClipboard(decodeResult.value)
  }
}

const copyResultText = async () => {
  if (resultText.value) {
    await copyToClipboard(resultText.value)
  }
}

const copyModalResult = async () => {
  if (modalResult.value) {
    await copyToClipboard(modalResult.value)
  }
}

const scanAgain = () => {
  // Clear previous result
  scanResult.value = ''

  // Restart scanning
  if (cameraStream.value) {
    startScanning()
  }
}

const decodeAgain = () => {
  resetDecodeState()
  // 重置后立即触发文件选择器，让用户可以继续上传新的图片
  setTimeout(() => {
    triggerFileUpload()
  }, 100)
}

const resetDecodeState = () => {
  // 重置所有状态
  uploadResult.value = ''
  urlResult.value = ''
  urlInput.value = ''
  uploadError.value = ''
  isProcessing.value = false
  isUploading.value = false
  processingFiles.value = []
  showUploadingStatus.value = false
  showUploadError.value = false

  // 重置文件输入框
  if (uploadInput.value) {
    uploadInput.value.value = ''
  }
}

const goToHome = () => {
  // 跳转到首页并传递解码结果
  const decodedContent = scanResult.value || uploadResult.value || urlResult.value
  if (decodedContent) {
    // 使用 query 参数传递解码结果
    router.push({
      path: '/qrcode',
      query: {
        content: decodedContent,
        from: 'decode'
      }
    })
  } else {
    router.push('/qrcode')
  }
}

const generateQR = () => {
  console.log('Generate QR code')
}

const generateFromResult = () => {
  console.log('Generate QR from result')
}

const returnToMain = async () => {
  await stopCamera()
}

const toggleFullscreen = () => {
  console.log('Toggle fullscreen')
}

// 摄像头全屏功能
const toggleCameraFullscreen = async () => {
  const cameraContainer = document.querySelector('.deqr-item-left') as HTMLElement

  if (!cameraContainer) {
    console.error('找不到摄像头容器')
    return
  }

  try {
    if (!document.fullscreenElement) {
      // 进入全屏
      await cameraContainer.requestFullscreen()
      console.log('摄像头进入全屏模式')
    } else {
      // 退出全屏
      await document.exitFullscreen()
      console.log('摄像头退出全屏模式')
    }
  } catch (error) {
    console.error('全屏切换失败:', error)
    // 显示用户友好的错误提示
    alert('全屏功能不可用，可能是浏览器不支持或权限不足')
  }
}

const continueScan = () => {
  console.log('Continue scan')
}

const continueModalScan = () => {
  console.log('Continue modal scan')
}

const closeResultDialog = () => {
  console.log('Close result dialog')
}

const closeResult = () => {
  console.log('Close result')
}

const closeQrStyle = () => {
  console.log('Close QR style')
}

const scanModalAgain = () => {
  console.log('Scan modal again')
}

// Modal methods
const closeDeleteModal = () => {
  showDeleteModal.value = false
}

const cancelDelete = () => {
  closeDeleteModal()
}

const confirmDelete = () => {
  console.log('Confirm delete')
  closeDeleteModal()
}

const closeEmptyModal = () => {
  showEmptyModal.value = false
}

const cancelEmpty = () => {
  closeEmptyModal()
}

const confirmEmpty = () => {
  console.log('Confirm empty')
  closeEmptyModal()
}

const closeExportSettingModal = () => {
  showExportSettingModal.value = false
}

const confirmExportSettings = () => {
  console.log('Export settings confirmed')
  closeExportSettingModal()
}

const closeHtmlScanModal = () => {
  showHtmlScanModal.value = false
}

const closeCommentModal = () => {
  console.log('Close comment modal')
}

const cancelComment = () => {
  console.log('Cancel comment')
}

const submitComment = () => {
  console.log('Submit comment')
}

const switchTab = (tab: string) => {
  currentTab.value = tab
  console.log('Switch to tab:', tab)
}

// Initialize page functionality
const initializePage = () => {
  // Set up router base
  ;(window as any).routerBase = "/"

  // Initialize context
  const ssrContext = {
    user: null,
    renderAt: Date.now(),
    hitCache: 2,
    referer: "",
    userAgent: navigator.userAgent
  }
  ;(window as any).__ssr_context = ssrContext

  // 设置默认的扫描提示文字
  scannerHeaderText.value = ''  // 可以设置顶部提示文字
  scannerBottomText.value = ''  // 可以设置底部提示文字

  console.log('Decoder page initialized')
}


// Outline navigation functions
const initOutlineNavigation = () => {
  nextTick(() => {
    collectHeaders()
    setupScrollListener()
  })
}

const collectHeaders = () => {
  // Collect h2 and h3 elements from the article content
  const headers = document.querySelectorAll('#wordpress_article_info_box h2, #wordpress_article_info_box h3')
  outlineItems.value = Array.from(headers).map((header) => ({
    text: header.textContent || '',
    tagName: header.tagName,
    element: header as HTMLElement
  }))

  // Set the first item as active by default
  if (outlineItems.value.length > 0) {
    activeOutlineIndex.value = 0
  }

  // Show or hide outline container based on whether there are headers
  if (outlineWrapper.value) {
    if (outlineItems.value.length > 0) {
      outlineWrapper.value.style.display = 'block'
      outlineContainer.value?.classList.add('hasOutline')
    } else {
      outlineWrapper.value.style.display = 'none'
      outlineContainer.value?.classList.remove('hasOutline')
    }
  }

  // Sync initial state
  syncActiveHeader()
}

const setupScrollListener = () => {
  const throttledSync = throttle(syncActiveHeader, 200)
  window.addEventListener('scroll', throttledSync)

  // Store cleanup function
  scrollCleanup = () => {
    window.removeEventListener('scroll', throttledSync)
  }
}

const syncActiveHeader = () => {
  if (isScrolling.value || outlineItems.value.length === 0) return

  let activeIndex = 0 // Default to first item
  const scrollTop = window.scrollY
  const headerOffsetTop = 100 // Offset for header detection

  // Find the current active header based on scroll position
  for (let i = 0; i < outlineItems.value.length; i++) {
    const element = outlineItems.value[i].element
    const elementTop = element.offsetTop - headerOffsetTop

    if (scrollTop >= elementTop) {
      activeIndex = i
    } else {
      break
    }
  }

  activeOutlineIndex.value = activeIndex
}

const scrollToHeader = (item: { element: HTMLElement, text: string }, index: number) => {
  if (activeOutlineIndex.value === index || isScrolling.value) return

  activeOutlineIndex.value = index
  isScrolling.value = true

  // Smooth scroll to the target header
  const offsetTop = item.element.offsetTop
  window.scrollTo({
    top: offsetTop,
    behavior: 'smooth'
  })

  // Reset scrolling flag after animation
  setTimeout(() => {
    isScrolling.value = false
  }, 800)
}

const throttle = (fn: Function, threshold: number) => {
  let last = 0
  let timer: number | null = null

  return function (...args: any[]) {
    const now = Date.now()

    if (now - last < threshold) {
      if (timer) window.clearTimeout(timer)
      timer = window.setTimeout(() => {
        fn.apply(this, args)
        last = Date.now()
      }, threshold)
      return
    }

    last = now
    return fn.apply(this, args)
  }
}

let scrollCleanup: (() => void) | null = null

// Lifecycle hooks
onMounted(async () => {
  console.log('🌟 QR码解码器正在启动...')

  // 强制重置状态
  uploadResult.value = ''
  urlResult.value = ''
  urlInput.value = ''
  scanResult.value = ''

  initializePage()

  // Initialize outline navigation after DOM is ready
  initOutlineNavigation()

  // Load external scripts and test functionality
  await loadExternalScripts()

  // DOM渲染完成，但不自动启动摄像头，等待用户点击
  nextTick(() => {
    console.log('✓ 摄像头组件准备就绪，等待用户启动')
  })

  console.log('🎉 QR码解码器启动完成')
})

onUnmounted(() => {
  // Cleanup scroll listener
  if (scrollCleanup) {
    scrollCleanup()
  }

  // Cleanup camera resources
  stopCamera()
})

// 测试和调试功能
const testQRRecognition = async () => {
  console.log('📈 正在测试QR码识别功能...')

  // 测试jsQR库加载
  try {
    const jsQR = await loadJsQRLibrary()
    if (jsQR) {
      console.log('✓ jsQR库加载成功')
      console.log('• jsQR版本:', jsQR.version || '未知')
    } else {
      console.error('✗ jsQR库加载失败')
    }
  } catch (error) {
    console.error('✗ jsQR库加载错误:', error)
  }

  // 测试摄像头支持
  if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
    console.log('✓ 摄像头API支持')
    try {
      const devices = await navigator.mediaDevices.enumerateDevices()
      const videoDevices = devices.filter(device => device.kind === 'videoinput')
      console.log(`• 找到 ${videoDevices.length} 个视频输入设备`)
      videoDevices.forEach((device, index) => {
        console.log(`  - 设备${index + 1}: ${device.label || '未命名设备'}`)
      })
    } catch (error) {
      console.warn('⚠️ 无法查询摄像头设备:', error)
    }
  } else {
    console.error('✗ 摄像头API不支持')
  }

  // 测试剪贴板支持
  if (navigator.clipboard) {
    console.log('✓ 剪贴板API支持')
  } else {
    console.warn('⚠️ 剪贴板API不支持，将使用备用方案')
  }

  // 测试本地存储
  try {
    localStorage.setItem('qr-test', 'test')
    localStorage.removeItem('qr-test')
    console.log('✓ 本地存储支持')
  } catch (error) {
    console.warn('⚠️ 本地存储不支持:', error)
  }

  console.log('🎉 QR码识别功能测试完成')
}

// 显示系统信息
const showSystemInfo = () => {
  console.log('📊 系统环境信息:')
  console.log(`• 用户代理: ${navigator.userAgent}`)
  console.log(`• 屏幕分辨率: ${screen.width}x${screen.height}`)
  console.log(`• 视窗尺寸: ${window.innerWidth}x${window.innerHeight}`)
  console.log(`• 设备像素比: ${window.devicePixelRatio || 1}`)
  console.log(`• 语言: ${navigator.language}`)
  console.log(`• 平台: ${navigator.platform}`)
  console.log(`• 在线状态: ${navigator.onLine ? '在线' : '离线'}`)
}

const loadExternalScripts = async () => {
  console.log('🚀 正在初始化QR码扫描器...')

  // 显示系统信息
  showSystemInfo()

  // 测试功能
  await testQRRecognition()

  // 预加载jsQR库
  try {
    await loadJsQRLibrary()
    console.log('✓ jsQR库预加载成功')
  } catch (error) {
    console.error('✗ jsQR库预加载失败:', error)
  }

  console.log('✓ QR码扫描器初始化完成')
}
</script>

<!-- Import external CSS files -->
<style src="../../assets/css/490815b50ee0.css" scoped/>
<style src="../../assets/css/00b58f2b8f9a.css" scoped/>
<style src="../../assets/css/e88b6e80fbce.css" scoped/>
<style src="../../assets/css/f6d6073f1386.css" scoped/>
<style src="../../assets/css/c1a2dbc35903.css" scoped/>
<style src="../../assets/css/0ff6e05882a2.css" scoped/>
<style src="../../assets/css/f459a6026b11.css" scoped/>
<style src="../../assets/css/2034b15460f1.css" scoped/>
<style src="../../assets/css/5fd66d82cf52.css" scoped/>
<style src="../../assets/css/228034f02af3.css" scoped/>
<style src="../../assets/css/acfff1e57b0e.css" scoped/>
<style src="../../assets/css/3db6acd047a4.css" scoped/>
<style src="../../assets/css/550d0fc5c52a.css" scoped/>
<style src="../../assets/css/7272988962e3.css" scoped/>
<style src="../../assets/css/cac1baa43ce6.css" scoped/>
<style src="../../assets/css/963d993f037a.css" scoped/>
<style src="../../assets/css/82dc0233b1fb.css" scoped/>
<style src="../../assets/css/52f4b4a7ee30.css" scoped/>
<style src="../../assets/css/b64637f7e36e.css" scoped/> <!--右侧导航边栏-->

<style scoped>

/* 摄像头控制按钮样式 */
.camera-controls {
  position: absolute;
  top: 12px;
  right: 12px;
  display: flex;
  gap: 8px;
  z-index: 100;
}

.camera-control-btn {
  width: 36px;
  height: 36px;
  background: rgba(0, 0, 0, 0.6);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: white;
  transition: all 0.2s ease;
  backdrop-filter: blur(4px);
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.camera-control-btn:hover {
  background: rgba(0, 0, 0, 0.8);
  transform: scale(1.05);
}

.camera-close-btn:hover {
  background: rgba(239, 68, 68, 0.8);
}

.camera-fullscreen-btn:hover {
  background: rgba(59, 130, 246, 0.8);
}

/* 全屏状态样式优化 */
.deqr-item-left:fullscreen {
  background: #000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
}

.deqr-item-left:fullscreen > div {
  width: 100%;
  height: 100%;
  border-radius: 0;
}

.deqr-item-left:fullscreen video {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

/* Inline styles from HTML */
#wechat-area {
  position: relative;
  height: 100px;
}

#wechat-qr {
  width: 100px;
  height: 100px;
  vertical-align: bottom;
}

.logo-in-qrcode {
  position: absolute;
  left: 40px;
  top: 40px;
  width: 20px;
  height: 20px;
}

.logo-in-qrcode img {
  width: 100%;
  height: 100%;
}

.scan-success {
  position: absolute;
  top: 0;
  left: 0;
  width: 100px;
  height: 100px;
  background-color: rgba(255,255,255,0.8);
  text-align: center;
  line-height: 100px;
  color: rgba(0, 0, 0, 0.87);
}

#email {
  width: 300px;
  border-radius: 4px;
}

.feedback-box .feedback-label {
  font-size: 14px;
  color: #777;
  width: 95px;
  line-height: 38px;
  float: left;
}

.feedback-box .feedback-content-500 {
  width: 408px;
}

.feedback-box .feedback-content {
  max-width: 100%;
  float: left;
}

.feedback-box .feedback-content .radio-inline {
  color: #666;
  margin-top: 10px;
}

#error-message {
  font-size: 12px;
}

.mobile-scene-min-width {
  min-width: 1200px;
}

.bottom-white-line {
  border-bottom: 1px solid #fff;
}

.lity-content {
  max-width: 96%;
}

/* Force center alignment for upload result - complete fix with highest priority */
.upload-dropzone .upload-dropzone-content-wrapper .upload-dropzone-result-wrapper,
.upload-dropzone-result-wrapper {
  display: flex !important;
  justify-content: center !important;
  align-items: center !important;
  flex-direction: column !important;
  position: absolute !important;
  width: 100% !important;
  height: 100% !important;
  max-width: 100% !important;
  top: 0 !important;
  left: 0 !important;
  right: 0 !important;
  background-color: #fff !important;
  text-align: center !important;
  z-index: 10 !important;
  margin: 0 !important;
  padding: 0 !important;
}

/* 当使用v-show隐藏时确保不遮挡其他元素 */
.upload-dropzone-result-wrapper[style*="display: none"],
.upload-dropzone-result-wrapper[style="display: none;"] {
  z-index: -1 !important;
  pointer-events: none !important;
  opacity: 0 !important;
}

/* 确保初始上传界面元素显示在最上层 */
.upload-dropzone-content-wrapper > img,
.upload-dropzone-desc-wrapper,
.upload-dropzone-footer-wrapper {
  position: relative !important;
  z-index: 20 !important;
}

/* Override any conflicting flexbox styles */
.upload-dropzone-result-wrapper * {
  -webkit-box-flex: unset !important;
  -webkit-box-orient: unset !important;
  -webkit-box-direction: unset !important;
  -webkit-box-align: unset !important;
  -webkit-box-pack: unset !important;
}

/* Fix result-wrapper - reset all positioning with highest priority */
.upload-dropzone .upload-dropzone-content-wrapper .upload-dropzone-result-wrapper .result-wrapper,
.upload-dropzone-result-wrapper .result-wrapper {
  display: block !important;
  -webkit-box: none !important;
  -webkit-flex-flow: unset !important;
  max-width: 100% !important;
  width: 100% !important;
  text-align: center !important;
  padding: 16px 0 !important;
  margin: 0 auto !important;
  box-sizing: border-box !important;
  position: relative !important;
  left: 0 !important;
  right: 0 !important;
}

/* Fix title positioning - remove all left margins */
.upload-dropzone-result-wrapper .deqr-success-title {
  text-align: center !important;
  margin: 0 auto 12px auto !important;
  width: 100% !important;
  padding: 0 !important;
}

/* Fix text-wrapper - ensure proper centering */
.upload-dropzone-result-wrapper .text-wrapper {
  display: flex !important;
  justify-content: center !important;
  align-items: center !important;
  width: 100% !important;
  margin: 0 auto !important;
  padding: 0 !important;
}

/* Fix title-text - remove left margin completely */
.upload-dropzone-result-wrapper .title-text {
  text-align: center !important;
  margin: 0 !important;
  margin-right: 4px !important;
  padding: 0 !important;
  width: auto !important;
  display: block !important;
  word-wrap: break-word !important;
  white-space: normal !important;
  -webkit-box: none !important;
  -webkit-line-clamp: unset !important;
  -webkit-box-orient: unset !important;
  overflow: visible !important;
  text-overflow: clip !important;
}

/* Fix copy-area positioning */
.upload-dropzone-result-wrapper .copy-area {
  margin-left: 0 !important;
  margin: 0 !important;
  display: inline-block !important;
  position: relative !important;
  z-index: 20 !important;
  top: 0 !important;
}

/* Fix action buttons wrapper */
.upload-dropzone-result-wrapper .deqr-action-btns-wrapper {
  display: flex !important;
  justify-content: center !important;
  align-items: center !important;
  width: 100% !important;
  margin: 16px auto 0 auto !important;
  gap: 8px !important;
  padding: 0 !important;
}

/* deqr-item-left 容器样式确保 */
.deqr-item-left {
  width: 666px !important;
  height: 375px !important;
  margin-right: 16px !important;
  position: relative !important;
  background: rgba(255,255,255,1) !important;
}

/* 大屏幕适配 */
@media (min-width: 1200px) {
  .deqr-item-left {
    width: 793px !important;
    height: 446px !important;
  }
}

/* 视频元素优化样式 */
video {
  border-radius: 8px;
  display: block;
}

/* 主摄像头视频容器优化 */
#mainCameraVideo {
  width: 100% !important;
  height: 100% !important;
  object-fit: cover !important;
  border-radius: 8px !important;
  display: block !important;
}

/* 扫描视频优化 */
#scanVideoNew {
  object-fit: cover !important;
  border-radius: 8px !important;
  width: 100% !important;
  height: 100% !important;
}

/* HTML扫描模态框视频优化 */
.modal-body video {
  object-fit: cover !important;
  border-radius: 8px !important;
  width: 100% !important;
  height: 100% !important;
}

/* 扫描覆盖层样式 */
.scan-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 1;
}

/* 扫描线动画 */
.scanner-line-animation {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 200px;
  height: 200px;
  transform: translate(-50%, -50%);
  border: 2px solid rgba(255, 255, 255, 0.8);
  border-radius: 8px;
}

.scanner-line-animation-inner {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 2px;
  background: linear-gradient(90deg, transparent, #00ff00, transparent);
  animation: scanLine 2s linear infinite;
}

@keyframes scanLine {
  0% { transform: translateY(0); }
  100% { transform: translateY(196px); }
}

/* 扫描框角落标记 */
.scan-corner {
  position: absolute;
  width: 20px;
  height: 20px;
  border: 3px solid #00ff00;
}

.scan-corner.top-left {
  top: calc(50% - 100px);
  left: calc(50% - 100px);
  border-right: none;
  border-bottom: none;
}

.scan-corner.top-right {
  top: calc(50% - 100px);
  right: calc(50% - 100px);
  border-left: none;
  border-bottom: none;
}

.scan-corner.bottom-left {
  bottom: calc(50% - 100px);
  left: calc(50% - 100px);
  border-right: none;
  border-top: none;
}

.scan-corner.bottom-right {
  bottom: calc(50% - 100px);
  right: calc(50% - 100px);
  border-left: none;
  border-top: none;
}

/* 头部文字样式 */
.scanner-header-text {
  position: absolute;
  top: 20px;
  left: 50%;
  transform: translateX(-50%);
  color: #fff;
  font-size: 24px;
  font-weight: 500;
  text-align: center;
  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.8);
  z-index: 2;
}

/* 底部文字样式 */
.scanner-bottom-text {
  position: absolute;
  bottom: 20px;
  left: 50%;
  transform: translateX(-50%);
  color: #fff;
  font-size: 14px;
  font-weight: 400;
  text-align: center;
  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.8);
  z-index: 2;
}

/* 中央提示文字 */
.scanner-center-text {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  text-align: center;
  color: #fff;
  z-index: 3;
  margin-top: 120px;
}

.scanner-icon {
  font-size: 32px;
  margin-bottom: 12px;
}

.scanner-main-text {
  font-size: 18px;
  font-weight: 500;
  margin-bottom: 6px;
  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.8);
}

.scanner-sub-text {
  font-size: 14px;
  font-weight: 400;
  opacity: 0.9;
  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.8);
}

/* 扫描结果覆盖层 */
.scanner-result-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.8);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 10;
}

.scanner-result-content {
  background: rgba(255, 255, 255, 0.95);
  border-radius: 12px;
  padding: 24px;
  text-align: center;
  max-width: 80%;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
}

.scanner-result-text {
  font-size: 16px;
  margin-bottom: 16px;
  color: rgba(0, 0, 0, 0.85);
  font-weight: 500;
}

.scanner-result-url {
  background: #f5f5f5;
  border-radius: 8px;
  padding: 12px;
  margin-bottom: 16px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  word-break: break-all;
}

.result-area {
  flex: 1;
  font-size: 14px;
  color: rgba(0, 0, 0, 0.85);
  margin-right: 8px;
}

.copy-area {
  cursor: pointer;
  display: flex;
  align-items: center;
  color: #1890ff;
  font-size: 12px;
  padding: 4px 8px;
  border-radius: 4px;
  transition: background-color 0.2s;
}

.copy-area:hover {
  background: rgba(24, 144, 255, 0.1);
}

.copy-text {
  margin-right: 4px;
}

.scan-action-btns {
  display: flex;
  gap: 12px;
  justify-content: center;
  margin-bottom: 12px;
}

.scan-again-btn,
.scan-home-btn {
  padding: 8px 16px;
  border-radius: 6px;
  cursor: pointer;
  font-size: 14px;
  transition: all 0.2s;
}

.scan-again-btn {
  background: #1890ff;
  color: white;
}

.scan-again-btn:hover {
  background: #40a9ff;
}

.scan-home-btn {
  background: #f0f0f0;
  color: rgba(0, 0, 0, 0.65);
}

.scan-home-btn:hover {
  background: #e6e6e6;
}

.scanner-result-footer {
  font-size: 12px;
  color: rgba(0, 0, 0, 0.45);
}

/* 响应式设计 */
@media (max-width: 800px) {
  .scanner-header-text {
    font-size: 18px;
  }

  .scanner-bottom-text {
    font-size: 12px;
  }

  .scanner-main-text {
    font-size: 16px;
  }

  .scanner-sub-text {
    font-size: 12px;
  }
}

/* 浮动提示文字样式 */
.upload-status-float {
  position: absolute;
  bottom: -25px;  /* 改为负值，让文字下移到描述区域外 */
  left: 50%;
  transform: translateX(-50%);
  font-size: 11px;
  color: rgba(0, 0, 0, 0.45);
  white-space: nowrap;
  z-index: 30;
  animation: pulse 1.5s ease-in-out infinite;
}

@keyframes pulse {
  0%, 100% {
    opacity: 0.6;
  }
  50% {
    opacity: 1;
  }
}

.upload-error-float {
  position: absolute;
  bottom: -30px;  /* 改为负值，让文字下移到描述区域外 */
  left: 50%;
  transform: translateX(-50%);
  font-size: 11px;
  color: #faad14;
  white-space: nowrap;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 4px;
  animation: fadeIn 0.3s ease-in-out;
}

@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateX(-50%) translateY(5px);
  }
  to {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
  }
}

.upload-error-float .error-text {
  color: #faad14;
}

</style>
